/**
 * Canvas思维导图实现
 * 功能：
 * 1. 节点的创建、编辑和删除
 * 2. 画布的缩放和平移
 * 3. 节点的拖拽和选择
 */
class MindMap {
    constructor(canvasId, options = {}) {
        // 获取Canvas元素
        this.canvas = document.getElementById(canvasId);
        this.ctx = this.canvas.getContext('2d');
        
        // 设置Canvas大小为窗口大小
        this.resizeCanvas();
        window.addEventListener('resize', () => this.resizeCanvas());
        
        // 当前编辑的节点
        this.editingNode = null;
        
        // 当前鼠标悬停的节点
        this.hoverNode = null;
        
        // 事件回调函数
        this.eventCallbacks = {
            onNodeSelect: options.onNodeSelect || null,
            onNodeActivate: options.onNodeActivate || null,
            onNodeEdit: options.onNodeEdit || null,
            onNodeDelete: options.onNodeDelete || null,
            onNodeAdd: options.onNodeAdd || null,
            onNodeCollapse: options.onNodeCollapse || null,
            onNodeExpand: options.onNodeExpand || null
        };
        
        // 默认配置与用户配置合并
        this.options = Object.assign({
            nodeWidth: 120,
            nodeHeight: 40,
            levelGap: 80,     // 减小层级间距
            siblingGap: 20,   // 同级节点间距
            fontSize: 14,
            fontFamily: 'Arial',
            nodeFill: '#ffffff',
            nodeStroke: '#333333',
            selectedNodeFill: '#e1f5fe',
            lineColor: '#666666',
            textColor: '#333333',
            cornerRadius: 5,   // 节点圆角
            tagFontSize: 10,   // 标签字体大小
            tagPadding: 4,     // 标签内边距
            tagMargin: 4,      // 标签外边距
            tagCornerRadius: 3, // 标签圆角
            // 标签颜色配置
            tagColors: {
                'default': { bg: '#e0e0e0', text: '#333333' },
                '重要': { bg: '#f44336', text: '#ffffff' },
                '进行中': { bg: '#2196f3', text: '#ffffff' },
                '完成': { bg: '#4caf50', text: '#ffffff' },
                '待办': { bg: '#ff9800', text: '#ffffff' }
            }
        }, options);
        
        // 确保用户配置的tagColors包含default颜色
        if (!this.options.tagColors.default) {
            this.options.tagColors.default = { bg: '#e0e0e0', text: '#333333' };
        }
        
        // 视图状态
        this.scale = 1;
        this.offsetX = this.canvas.width / 2;
        this.offsetY = this.canvas.height / 2;
        
        // 交互状态
        this.dragging = false;
        this.dragNode = false;
        this.lastX = 0;
        this.lastY = 0;
        this.selectedNode = null;
        
        // 初始化数据
        this.root = null;
        
        // 设置默认数据
        this.setDefaultData();
        
        // 绑定事件
        this.setupEvents();
        
        // 初始渲染
        this.render();
    }
    
    // 设置Canvas大小
    resizeCanvas() {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
        this.render();
    }
    
    // 设置默认数据
    setDefaultData() {
        // 注意：这里不需要手动设置uid，因为processNode方法会自动为每个节点生成uid
        // 当导入已有数据时，会保留原有uid
        const defaultData = {
            data: { text: '中心主题', tags: ['重要'] },
            children: [
                { 
                    data: { text: '子主题1', tags: ['进行中'] }, 
                    children: [
                        { data: { text: '子主题1.1', tags: ['待办'] }, children: [] },
                        { data: { text: '这是一个非常长的文本节点，用于测试长文本节点与兄弟节点宽度保持一致的功能', tags: ['完成'] }, children: [] }
                    ] 
                },
                { data: { text: '子主题2' }, children: [] },
                { 
                    data: { text: '子主题3', tags: ['重要', '进行中'] }, 
                    children: [
                        { data: { text: '子主题3.1' }, children: [] },
                        { data: { text: '另一个长文本节点测试', tags: ['待办'] }, children: [] }
                    ] 
                }
            ]
        };
        
        this.setData(defaultData);
    }
    
    // 设置思维导图数据
    setData(data) {
        this.root = this.processNode(data, 0, 0);
        this.calculateLayout();
        this.render();
    }
    
    // 导出思维导图数据为JSON格式
    exportData() {
        if (!this.root) return null;
        return this.nodeToJson(this.root);
    }
    
    // 将节点转换为JSON格式
    nodeToJson(node) {
        return {
            data: {
                text: node.text,
                tags: node.tags || [] // 导出标签数据
            },
            uid: node.uid,
            collapsed: node.collapsed, // 保存折叠状态
            children: node.children.map(child => this.nodeToJson(child))
        };
    }
    
    // 生成唯一ID
    generateUid() {
        return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
    }
    
    // 处理节点数据
    processNode(data, level, index) {
        // 兼容旧数据结构，如果直接提供了text属性而不是data对象
        const nodeText = data.data ? data.data.text : data.text;
        // 处理标签数据，如果存在则使用，否则为空数组
        const nodeTags = data.data && data.data.tags ? data.data.tags : (data.tags || []);
        
        return {
            text: nodeText, // 保留text属性以兼容现有代码
            data: {
                text: nodeText,
                tags: nodeTags // 添加标签属性
            },
            tags: nodeTags, // 保留直接访问的能力
            level,
            index,
            uid: data.uid || this.generateUid(), // 使用现有uid或生成新的uid
            children: data.children ? data.children.map((child, i) => 
                this.processNode(child, level + 1, i)
            ) : [],
            collapsed: data.collapsed || false, // 节点折叠状态，默认为展开
            x: 0,
            y: 0,
            width: this.options.nodeWidth, // 初始宽度，后续会根据文本内容调整
            height: this.options.nodeHeight, // 初始高度，后续会根据文本内容调整
            textLines: [] // 用于存储换行后的文本行
        };
    }
    
    // 获取思维导图的最大层级深度
    getMaxLevel(node, currentLevel = 0) {
        if (!node) return currentLevel - 1;
        
        let maxLevel = currentLevel;
        
        if (node.children && node.children.length > 0) {
            node.children.forEach(child => {
                const childMaxLevel = this.getMaxLevel(child, currentLevel + 1);
                maxLevel = Math.max(maxLevel, childMaxLevel);
            });
        }
        
        return maxLevel;
    }
    
    // 计算布局
    calculateLayout() {
        // 设置Canvas字体以便测量文本
        this.ctx.font = `${this.options.fontSize}px ${this.options.fontFamily}`;
        
        // 保存所有节点的折叠状态
        const saveCollapseState = (node) => {
            if (!node) return {};
            
            const stateMap = {};
            stateMap[node.uid] = node.collapsed;
            
            if (node.children && node.children.length > 0) {
                node.children.forEach(child => {
                    const childState = saveCollapseState(child);
                    Object.assign(stateMap, childState);
                });
            }
            
            return stateMap;
        };
        
        // 恢复所有节点的折叠状态
        const restoreCollapseState = (node, stateMap) => {
            if (!node || !stateMap) return;
            
            if (node.uid in stateMap) {
                node.collapsed = stateMap[node.uid];
            }
            
            if (node.children && node.children.length > 0) {
                node.children.forEach(child => {
                    restoreCollapseState(child, stateMap);
                });
            }
        };
        
        // 保存当前所有节点的折叠状态
        const collapseStateMap = saveCollapseState(this.root);
        
        // 辅助函数：更新节点的文本换行
        const updateTextLines = (node, nodeWidth, padding) => {
            node.textLines = [];
            // 使用节点的text属性，该属性在processNode中已经设置
            let remainingText = node.text;
            const maxLineWidth = nodeWidth - padding * 2;
            
            while (remainingText.length > 0) {
                let lineText = remainingText;
                let lineWidth = this.ctx.measureText(lineText).width;
                
                // 如果文本宽度超过最大行宽，需要换行
                if (lineWidth > maxLineWidth) {
                    // 查找合适的换行点
                    let breakIndex = Math.floor(remainingText.length * (maxLineWidth / lineWidth));
                    
                    // 向前查找空格或标点作为换行点
                    while (breakIndex > 0 && 
                           !/\s|，|。|、|；|：|！|？|,|\.|;|:|!|\?/.test(remainingText.charAt(breakIndex))) {
                        breakIndex--;
                    }
                    
                    // 如果没找到合适的换行点，就强制在某个字符处换行
                    if (breakIndex === 0) {
                        breakIndex = Math.floor(remainingText.length * (maxLineWidth / lineWidth));
                    }
                    
                    lineText = remainingText.substring(0, breakIndex + 1);
                    remainingText = remainingText.substring(breakIndex + 1);
                } else {
                    remainingText = '';
                }
                
                node.textLines.push(lineText);
            }
        };
        
        // 第一阶段：计算每个节点的初始尺寸和收集同级节点
        const calculateInitialSizes = (node) => {
            // 最小宽度和最大宽度限制
            const minWidth = this.options.nodeWidth;
            const maxWidth = this.options.nodeWidth * 3; // 最大宽度为默认宽度的3倍
            const padding = 20; // 文本与节点边缘的内边距
            
            // 测量文本宽度 - 改进：确保准确测量文本宽度
            const textWidth = this.ctx.measureText(node.text).width + padding * 2;
            
            // 确定节点宽度（在最小和最大宽度之间）- 改进：确保节点宽度能够适应文本
            node.width = Math.min(maxWidth, Math.max(minWidth, textWidth));
            
            // 收集同级节点（按层级和父节点分组）
            if (!this.siblingGroups) {
                this.siblingGroups = new Map();
            }
            
            if (node.children && node.children.length > 0) {
                // 为子节点创建一个唯一的分组键
                const groupKey = `level_${node.level + 1}_parent_${node.text}`;
                if (!this.siblingGroups.has(groupKey)) {
                    this.siblingGroups.set(groupKey, []);
                }
                
                // 将所有子节点添加到同一分组
                node.children.forEach(child => {
                    this.siblingGroups.get(groupKey).push(child);
                    // 递归处理子节点
                    calculateInitialSizes(child);
                });
            }
        };
        
        // 第二阶段：更新文本换行和节点高度（不再统一兄弟节点宽度）
        const normalizeSiblingWidths = () => {
            // 遍历所有同级节点分组
            this.siblingGroups.forEach((siblings, groupKey) => {
                // 处理每个节点，不再统一宽度
                siblings.forEach(node => {
                    const padding = 20;
                    
                    // 计算标签所需的宽度（现在标签将放在节点外部）
                    let tagWidth = 0;
                    if (node.tags && node.tags.length > 0) {
                        // 设置标签字体以便测量标签宽度
                        const originalFont = this.ctx.font;
                        this.ctx.font = `${this.options.tagFontSize}px ${this.options.fontFamily}`;
                        
                        // 计算所有标签的总宽度
                        node.tags.forEach(tag => {
                            tagWidth += this.ctx.measureText(tag).width + this.options.tagPadding * 2 + this.options.tagMargin;
                        });
                        
                        // 恢复原始字体
                        this.ctx.font = originalFont;
                    }
                    
                    // 保存标签宽度信息，用于后续绘制
                    // 注意：现在标签宽度不再计入节点宽度，而是单独保存
                    node.tagWidth = tagWidth;
                    
                    // 更新文本换行（使用节点自身的宽度，标签现在在外部）
                    updateTextLines(node, node.width, padding);
                    
                    // 更新节点高度
                    const lineHeight = this.options.fontSize * 1.2;
                    const textHeight = node.textLines.length * lineHeight;
                    
                    // 节点总高度 = 最大(默认高度, 文本高度+内边距)，不再加上标签高度
                    node.height = Math.max(this.options.nodeHeight, textHeight + padding);
                });
            });
        };
        
        // 第三阶段：计算节点高度和布局信息
        const calculateNodeSize = (node) => {
            const padding = 20;
            
            // 文本换行处理（确保已经完成）
            if (!node.textLines || node.textLines.length === 0) {
                updateTextLines(node, node.width, padding);
            }
            
            // 根据文本行数计算节点高度
            const lineHeight = this.options.fontSize * 1.2; // 行高为字体大小的1.2倍
            const textHeight = node.textLines.length * lineHeight;
            
            // 使用已计算的标签宽度
            let tagWidth = node.tagWidth || 0;
            
            // 节点总高度 = 最大(默认高度, 文本高度+内边距)，不再加上标签高度
            node.height = Math.max(this.options.nodeHeight, textHeight + padding);
            
            // 递归计算子节点尺寸
            if (node.children && node.children.length > 0) {
                node.children.forEach(child => {
                    calculateNodeSize(child);
                });
            }
            
            // 计算子节点总高度（用于布局）
            if (!node.children || node.children.length === 0) {
                return node.height;
            }
            
            let totalHeight = 0;
            node.children.forEach(child => {
                // 增加间距，确保子节点之间有足够的空间
                totalHeight += child.height + this.options.siblingGap;
            });
            
            return Math.max(node.height, totalHeight - this.options.siblingGap);
        };
        
        // 注意：三个阶段的计算在positionNode调用前执行

        // 存储每个层级的节点垂直位置信息，用于防止不同分支的节点重叠
        const levelVerticalRanges = new Map();
        
        // 预处理：为每个层级创建空数组，避免后续判断是否存在
        const maxLevel = this.getMaxLevel(this.root);
        for (let i = 0; i <= maxLevel; i++) {
            levelVerticalRanges.set(i, []);
        }
        
        // 获取节点及其所有子节点的总高度
        const getNodeTotalHeight = (node) => {
            if (!node.children || node.children.length === 0) {
                return node.height;
            }
            
            let totalHeight = 0;
            node.children.forEach(child => {
                totalHeight += getNodeTotalHeight(child);
            });
            
            // 加上子节点之间的间距
            if (node.children.length > 1) {
                totalHeight += (node.children.length - 1) * this.options.siblingGap * 0.8;
            }
            
            return totalHeight;
        };
        
        // 定位节点
        const positionNode = (node, x, y) => {
            // 设置节点的x坐标
            node.x = x;
            
            // 如果不是根节点，需要检查并调整垂直位置
            if (node !== this.root) {
                const nodeHeight = node.height;
                const siblingGap = this.options.siblingGap;
                
                // 获取当前层级的已有节点范围
                const currentLevelRanges = levelVerticalRanges.get(node.level) || [];
                
                // 初始垂直位置
                let adjustedY = y;
                
                // 计算节点的实际占用空间（包括标签）
                const tagHeight = node.tags && node.tags.length > 0 ? 
                    (this.options.tagFontSize + this.options.tagPadding * 2) : 0;
                const totalNodeHeight = nodeHeight + tagHeight;
                
                // 计算节点的总高度（包括所有子节点）
                const nodeTotalHeight = getNodeTotalHeight(node);
                
                // 统一的安全间距
                const safetyGap = siblingGap;
                
                // 检查是否与同层级已有节点重叠
                let hasOverlap = true;
                let maxIterations = 100; // 防止无限循环
                let iterations = 0;
                
                while (hasOverlap && iterations < maxIterations) {
                    iterations++;
                    hasOverlap = false;
                    
                    // 更新节点的上下边界，考虑子节点的总高度
                    const nodeTop = adjustedY - nodeTotalHeight / 2;
                    const nodeBottom = adjustedY + nodeTotalHeight / 2;
                    
                    // 检查与每个已有节点的重叠情况
                    for (const range of currentLevelRanges) {
                        // 检测重叠：两个区间有交集
                        if (!(nodeBottom + safetyGap <= range.top || nodeTop >= range.bottom + safetyGap)) {
                            hasOverlap = true;
                            // 根据节点总高度调整额外间距
                            const extraSpacing = Math.max(10, nodeTotalHeight * 0.1);
                            adjustedY = range.bottom + nodeTotalHeight / 2 + safetyGap + extraSpacing;
                            break;
                        }
                    }
                }
                
                // 使用调整后的位置
                node.y = adjustedY;
            } else {
                // 根节点垂直居中
                node.y = 0;
            }
            
            // 记录当前节点的垂直范围，考虑子节点的总高度
            const nodeTotalHeight = getNodeTotalHeight(node);
            const nodeTop = node.y - nodeTotalHeight / 2;
            const nodeBottom = node.y + nodeTotalHeight / 2;
            
            // 更新该层级的垂直范围记录
            levelVerticalRanges.get(node.level).push({ top: nodeTop, bottom: nodeBottom, y: node.y });
            levelVerticalRanges.get(node.level).sort((a, b) => a.y - b.y);
            
            if (node.children && node.children.length > 0) {
                // 计算子节点的垂直位置
                let totalChildrenHeight = 0;
                node.children.forEach(child => {
                    totalChildrenHeight += getNodeTotalHeight(child);
                });
                
                // 减小子节点间的垂直间距
                totalChildrenHeight += (node.children.length - 1) * this.options.siblingGap * 0.8;
                
                // 计算第一个子节点的起始垂直位置
                // 确保子节点整体高度的中心点与父节点对齐
                let currentY = node.y - totalChildrenHeight / 2;
                
                // 定位每个子节点
                for (let i = 0; i < node.children.length; i++) {
                    const child = node.children[i];
                    const childTotalHeight = getNodeTotalHeight(child);
                    
                    // 定位子节点，使用当前计算的垂直位置
                    // 将子节点的中心点设置为当前Y位置加上子节点高度的一半
                    positionNode(child, x + node.width + this.options.levelGap, currentY + childTotalHeight / 2);
                    
                    // 更新下一个子节点的起始位置
                    if (i < node.children.length - 1) {
                        const nextChild = node.children[i + 1];
                        // 减小子节点间的垂直间距
                        currentY += childTotalHeight + this.options.siblingGap * 0.8;
                    }
                }
            }
        };
        
        // 从根节点开始计算
        this.siblingGroups = new Map(); // 重置同级节点分组
        calculateInitialSizes(this.root); // 第一阶段
        normalizeSiblingWidths();        // 第二阶段
        this.root.height = calculateNodeSize(this.root); // 第三阶段
        positionNode(this.root, -this.root.width / 2, 0); // 修复：根节点垂直居中于原点
        
        // 恢复所有节点的折叠状态
        restoreCollapseState(this.root, collapseStateMap);
    }
    
    // 创建右键菜单
    createContextMenu() {
        // 检查是否已存在菜单，如果存在则移除
        const existingMenu = document.getElementById('node-context-menu');
        if (existingMenu) {
            existingMenu.remove();
        }
        
        // 创建菜单元素
        const menu = document.createElement('div');
        menu.id = 'node-context-menu';
        menu.style.position = 'absolute';
        menu.style.zIndex = '1000';
        menu.style.backgroundColor = 'white';
        menu.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
        menu.style.borderRadius = '4px';
        menu.style.padding = '5px 0';
        menu.style.display = 'none';
        
        // 添加菜单项
        const addChildItem = document.createElement('div');
        addChildItem.textContent = '添加子节点';
        addChildItem.style.padding = '8px 12px';
        addChildItem.style.cursor = 'pointer';
        addChildItem.style.fontSize = '14px';
        addChildItem.addEventListener('mouseover', () => {
            addChildItem.style.backgroundColor = '#f0f0f0';
        });
        addChildItem.addEventListener('mouseout', () => {
            addChildItem.style.backgroundColor = 'transparent';
        });
        
        const toggleCollapseItem = document.createElement('div');
        toggleCollapseItem.style.padding = '8px 12px';
        toggleCollapseItem.style.cursor = 'pointer';
        toggleCollapseItem.style.fontSize = '14px';
        toggleCollapseItem.addEventListener('mouseover', () => {
            toggleCollapseItem.style.backgroundColor = '#f0f0f0';
        });
        toggleCollapseItem.addEventListener('mouseout', () => {
            toggleCollapseItem.style.backgroundColor = 'transparent';
        });
        
        const deleteItem = document.createElement('div');
        deleteItem.textContent = '删除节点';
        deleteItem.style.padding = '8px 12px';
        deleteItem.style.cursor = 'pointer';
        deleteItem.style.fontSize = '14px';
        deleteItem.addEventListener('mouseover', () => {
            deleteItem.style.backgroundColor = '#f0f0f0';
        });
        deleteItem.addEventListener('mouseout', () => {
            deleteItem.style.backgroundColor = 'transparent';
        });
        
        // 添加菜单项到菜单
        menu.appendChild(addChildItem);
        menu.appendChild(toggleCollapseItem);
        menu.appendChild(deleteItem);
        
        // 添加到DOM
        document.getElementById('canvas-container').appendChild(menu);
        
        return { menu, addChildItem, toggleCollapseItem, deleteItem };
    }
    
    // 显示右键菜单
    showContextMenu(x, y, node) {
        const { menu, addChildItem, toggleCollapseItem, deleteItem } = this.createContextMenu();
        
        // 设置菜单位置
        menu.style.left = `${x}px`;
        menu.style.top = `${y}px`;
        menu.style.display = 'block';
        
        // 设置菜单项点击事件
        addChildItem.addEventListener('click', () => {
            this.addChild(node, '新节点');
            menu.remove();
        });
        
        // 设置折叠/展开菜单项
        if (node.children && node.children.length > 0) {
            toggleCollapseItem.textContent = node.collapsed ? '展开节点' : '折叠节点';
            toggleCollapseItem.addEventListener('click', () => {
                this.toggleNodeCollapse(node);
                menu.remove();
            });
        } else {
            toggleCollapseItem.style.color = '#ccc';
            toggleCollapseItem.style.cursor = 'not-allowed';
            toggleCollapseItem.textContent = '折叠节点';
        }
        
        // 根节点不能删除
        if (node === this.root) {
            deleteItem.style.color = '#ccc';
            deleteItem.style.cursor = 'not-allowed';
        } else {
            deleteItem.addEventListener('click', () => {
                this.removeNode(node);
                menu.remove();
            });
        }
        
        // 点击其他区域关闭菜单
        const closeMenu = (e) => {
            if (!menu.contains(e.target)) {
                menu.remove();
                document.removeEventListener('click', closeMenu);
            }
        };
        
        // 延迟添加事件，防止立即触发
        setTimeout(() => {
            document.addEventListener('click', closeMenu);
        }, 0);
    }
    
    // 设置事件监听
    setupEvents() {
        // 鼠标按下事件
        this.canvas.addEventListener('mousedown', (e) => {
            // 如果是右键点击，不执行默认的mousedown行为
            if (e.button === 2) return;
            
            const rect = this.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 检查是否点击了节点或指示器
            const result = this.findNodeAt(x, y);
            
            if (result) {
                if (result.isIndicator) {
                    // 点击了折叠/展开指示器
                    this.toggleNodeCollapse(result.node);
                } else {
                    // 点击了节点本身
                    this.selectedNode = result.node;
                    this.dragNode = true;
                    this.triggerNodeSelect(result.node);
                    this.triggerNodeActivate(result.node);
                }
            } else {
                // 点击了空白区域
                this.dragging = true;
                // 取消选中节点
                if (this.selectedNode) {
                    this.selectedNode = null;
                    // 触发节点取消选中事件
                    if (this.eventCallbacks.onNodeSelect) {
                        this.eventCallbacks.onNodeSelect(null);
                    }
                }
            }
            
            this.lastX = x;
            this.lastY = y;
            this.render();
        });
        
        // 右键菜单事件
        this.canvas.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            
            const rect = this.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 检查是否右键点击了节点
            const result = this.findNodeAt(x, y);
            
            if (result && !result.isIndicator) {
                this.selectedNode = result.node;
                this.render();
                this.showContextMenu(e.clientX, e.clientY, result.node);
            }
        });
        
        // 鼠标移动事件
        this.canvas.addEventListener('mousemove', (e) => {
            const rect = this.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 检查鼠标是否悬停在节点上
            const result = this.findNodeAt(x, y);
            if (result && !result.isIndicator) {
                if (this.hoverNode !== result.node) {
                    this.hoverNode = result.node;
                    this.render();
                }
            } else if (this.hoverNode) {
                this.hoverNode = null;
                this.render();
            }
            
            if (this.dragNode && this.selectedNode) {
                // 如果是根节点，不允许拖动
                if (this.selectedNode === this.root) return;
                
                const dx = (x - this.lastX) / this.scale;
                const dy = (y - this.lastY) / this.scale;
                
                this.selectedNode.x += dx;
                this.selectedNode.y += dy;
                
                this.lastX = x;
                this.lastY = y;
                this.render();
            } else if (this.dragging) {
                // 平移画布
                this.offsetX += (x - this.lastX);
                this.offsetY += (y - this.lastY);
                
                this.lastX = x;
                this.lastY = y;
                this.render();
            }
        });
        
        // 鼠标释放事件
        this.canvas.addEventListener('mouseup', () => {
            this.dragging = false;
            this.dragNode = false;
        });
        
        // 鼠标离开事件
        this.canvas.addEventListener('mouseleave', () => {
            this.dragging = false;
            this.dragNode = false;
        });
        
        // 鼠标滚轮事件 - 缩放
        this.canvas.addEventListener('wheel', (e) => {
            e.preventDefault();
            
            const rect = this.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 缩放因子
            const delta = e.deltaY > 0 ? 0.6 : 1.1;
            
            // 限制缩放范围
            const newScale = Math.max(0.5, Math.min(2, this.scale * delta));
            
            // 计算缩放中心点
            const scaleRatio = newScale / this.scale;
            this.offsetX = x - (x - this.offsetX) * scaleRatio;
            this.offsetY = y - (y - this.offsetY) * scaleRatio;
            
            this.scale = newScale;
            this.render();
        });
        
        // 双击事件 - 直接编辑节点
        this.canvas.addEventListener('dblclick', (e) => {
            const rect = this.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            const result = this.findNodeAt(x, y);
            if (result && !result.isIndicator) {
                // 创建编辑框
                this.createEditInput(result.node, x, y);
            }
        });
        
        // 监听点击事件，当点击编辑框外部时关闭编辑框
        document.addEventListener('click', (e) => {
            const editInput = document.getElementById('node-edit-input');
            if (editInput && e.target !== editInput) {
                this.finishEditing();
            }
        });
        
        // 添加节点按钮
        const addButton = document.getElementById('add-node');
        if (addButton) {
            addButton.addEventListener('click', () => {
                if (this.selectedNode) {
                    this.addChild(this.selectedNode, '新节点');
                } else {
                    alert('请先选择一个节点');
                }
            });
        }
        
        // 删除节点按钮
        const deleteButton = document.getElementById('delete-node');
        if (deleteButton) {
            deleteButton.addEventListener('click', () => {
                if (this.selectedNode && this.selectedNode !== this.root) {
                    this.removeNode(this.selectedNode);
                } else if (this.selectedNode === this.root) {
                    alert('不能删除根节点');
                } else {
                    alert('请先选择一个节点');
                }
            });
        }
        
        // 重置视图按钮
        const resetButton = document.getElementById('reset-view');
        if (resetButton) {
            resetButton.addEventListener('click', () => {
                this.scale = 1;
                this.offsetX = this.canvas.width / 2;
                this.offsetY = this.canvas.height / 2;
                this.render();
            });
        }

        // 复制节点按钮
        const copyButton = document.getElementById('copy-node');
        if (copyButton) {
            copyButton.addEventListener('click', () => {
                if (this.selectedNode && this.selectedNode !== this.root) {
                    this.copyNode(this.selectedNode);
                } else if (this.selectedNode === this.root) {
                    alert('不能复制根节点');
                } else {
                    alert('请先选择一个节点');
                }
            });
        }
    }
    
    // 查找指定位置的节点或指示器
    findNodeAt(x, y) {
        // 转换为画布坐标
        const canvasX = (x - this.offsetX) / this.scale;
        const canvasY = (y - this.offsetY) / this.scale;
        
        // 调试：输出点击坐标
        console.log('点击坐标:', { canvasX, canvasY });
        
        // 递归检查节点
        const checkNode = (node) => {
            if (!node) return null;
            
            // 首先检查是否点击了折叠/展开指示器
            if (node.children && node.children.length > 0) {
                const indicatorSize = 16;
                const indicatorX = node.x + node.width - indicatorSize - 8;
                const indicatorY = node.y + node.height / 2;
                
                // 计算指示器的点击区域（考虑缩放）
                const indicatorRegion = {
                    x: indicatorX - indicatorSize / 2,
                    y: indicatorY - indicatorSize / 2,
                    width: indicatorSize,
                    height: indicatorSize
                };
                
                // 调试：输出指示器区域
                console.log('指示器区域:', {
                    nodeText: node.text,
                    indicatorX: indicatorRegion.x,
                    indicatorY: indicatorRegion.y,
                    indicatorWidth: indicatorRegion.width,
                    indicatorHeight: indicatorRegion.height,
                    isInside: canvasX >= indicatorRegion.x && 
                             canvasX <= indicatorRegion.x + indicatorRegion.width && 
                             canvasY >= indicatorRegion.y && 
                             canvasY <= indicatorRegion.y + indicatorRegion.height
                });
                
                // 检查点击是否在指示器区域内
                if (canvasX >= indicatorRegion.x && 
                    canvasX <= indicatorRegion.x + indicatorRegion.width && 
                    canvasY >= indicatorRegion.y && 
                    canvasY <= indicatorRegion.y + indicatorRegion.height) {
                    return { node, isIndicator: true };
                }
            }
            
            // 然后检查是否点击了节点本身
            if (canvasX >= node.x && 
                canvasX <= node.x + node.width &&
                canvasY >= node.y - node.height / 2 && 
                canvasY <= node.y + node.height / 2) {
                return { node, isIndicator: false };
            }
            
            // 递归检查子节点，但只检查未折叠的节点的子节点
            if (node.children && !node.collapsed) {
                for (const child of node.children) {
                    const found = checkNode(child);
                    if (found) return found;
                }
            }
            
            return null;
        };
        
        return checkNode(this.root);
    }
    
    // 切换节点的折叠状态
    toggleNodeCollapse(node) {
        if (!node || !node.children || node.children.length === 0) return;
        
        // 切换折叠状态
        node.collapsed = !node.collapsed;
        
        // 触发折叠/展开事件
        if (node.collapsed) {
            this.triggerNodeCollapse(node);
        } else {
            this.triggerNodeExpand(node);
        }
        
        // 重新计算布局
        this.calculateLayout();
        
        // 重新渲染
        this.render();
        
        // 输出调试信息
        console.log('节点折叠状态切换:', {
            nodeText: node.text,
            collapsed: node.collapsed,
            childrenCount: node.children.length
        });
    }
    
    // 创建节点编辑输入框
    createEditInput(node, clientX, clientY) {
        // 移除已存在的编辑框
        this.finishEditing();
        
        // 计算编辑框位置
        const canvasRect = this.canvas.getBoundingClientRect();
        const nodeX = this.offsetX + node.x * this.scale;
        const nodeY = this.offsetY + node.y * this.scale;
        
        // 创建编辑容器
        const container = document.createElement('div');
        container.id = 'node-edit-container';
        container.style.position = 'absolute';
        container.style.left = `${nodeX}px`;
        container.style.top = `${nodeY}px`;
        container.style.width = `${node.width * this.scale}px`;
        container.style.zIndex = '1000';
        container.style.backgroundColor = '#ffffff';
        container.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
        container.style.borderRadius = `${this.options.cornerRadius}px`;
        container.style.padding = '10px';
        
        // 创建文本输入框
        const input = document.createElement('textarea');
        input.id = 'node-edit-input';
        input.value = node.text;
        input.style.width = '100%';
        input.style.height = `${node.height * this.scale}px`;
        input.style.fontSize = `${this.options.fontSize * this.scale}px`;
        input.style.fontFamily = this.options.fontFamily;
        input.style.border = '1px solid #ccc';
        input.style.borderRadius = `${this.options.cornerRadius}px`;
        input.style.padding = '5px';
        input.style.margin = '0 0 10px 0';
        input.style.textAlign = 'center';
        input.style.resize = 'none';
        input.style.overflow = 'hidden';
        
        // 创建标签标题
        const tagTitle = document.createElement('div');
        tagTitle.textContent = '标签:';
        tagTitle.style.fontSize = '14px';
        tagTitle.style.fontWeight = 'bold';
        tagTitle.style.marginBottom = '5px';
        
        // 创建标签容器
        const tagContainer = document.createElement('div');
        tagContainer.style.display = 'flex';
        tagContainer.style.flexWrap = 'wrap';
        tagContainer.style.gap = '5px';
        tagContainer.style.marginBottom = '10px';
        
        // 获取所有可用标签（从配置中获取）
        const availableTags = Object.keys(this.options.tagColors);
        
        // 当前节点的标签
        const nodeTags = node.tags || [];
        
        // 创建标签选择器
        availableTags.forEach(tag => {
            if (tag === 'default') return; // 跳过默认标签
            
            const tagColor = this.options.tagColors[tag];
            const tagElement = document.createElement('div');
            tagElement.textContent = tag;
            tagElement.style.backgroundColor = nodeTags.includes(tag) ? tagColor.bg : '#f0f0f0';
            tagElement.style.color = nodeTags.includes(tag) ? tagColor.text : '#333';
            tagElement.style.padding = '3px 8px';
            tagElement.style.borderRadius = '3px';
            tagElement.style.cursor = 'pointer';
            tagElement.style.fontSize = '12px';
            tagElement.style.transition = 'all 0.2s';
            
            // 点击标签切换选中状态
            tagElement.addEventListener('click', () => {
                const index = nodeTags.indexOf(tag);
                if (index === -1) {
                    // 添加标签
                    nodeTags.push(tag);
                    tagElement.style.backgroundColor = tagColor.bg;
                    tagElement.style.color = tagColor.text;
                } else {
                    // 移除标签
                    nodeTags.splice(index, 1);
                    tagElement.style.backgroundColor = '#f0f0f0';
                    tagElement.style.color = '#333';
                }
            });
            
            tagContainer.appendChild(tagElement);
        });
        
        // 创建按钮容器
        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.justifyContent = 'flex-end';
        buttonContainer.style.gap = '10px';
        
        // 创建确认按钮
        const confirmButton = document.createElement('button');
        confirmButton.textContent = '确认';
        confirmButton.style.padding = '5px 10px';
        confirmButton.style.backgroundColor = '#4CAF50';
        confirmButton.style.color = 'white';
        confirmButton.style.border = 'none';
        confirmButton.style.borderRadius = '3px';
        confirmButton.style.cursor = 'pointer';
        
        // 创建取消按钮
        const cancelButton = document.createElement('button');
        cancelButton.textContent = '取消';
        cancelButton.style.padding = '5px 10px';
        cancelButton.style.backgroundColor = '#f44336';
        cancelButton.style.color = 'white';
        cancelButton.style.border = 'none';
        cancelButton.style.borderRadius = '3px';
        cancelButton.style.cursor = 'pointer';
        
        // 添加按钮事件
        confirmButton.addEventListener('click', () => {
            this.finishEditing();
        });
        
        cancelButton.addEventListener('click', () => {
            this.cancelEditing();
        });
        
        // 组装编辑界面
        buttonContainer.appendChild(cancelButton);
        buttonContainer.appendChild(confirmButton);
        
        container.appendChild(input);
        container.appendChild(tagTitle);
        container.appendChild(tagContainer);
        container.appendChild(buttonContainer);
        
        // 存储当前编辑的节点
        this.editingNode = node;
        
        // 添加到DOM
        document.getElementById('canvas-container').appendChild(container);
        
        // 聚焦文本输入框
        input.focus();
        input.select();
        
        // 添加键盘事件
        input.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                this.finishEditing();
            } else if (e.key === 'Escape') {
                e.preventDefault();
                this.cancelEditing();
            }
        });
    }
    
    // 完成编辑
    finishEditing() {
        const container = document.getElementById('node-edit-container');
        const input = document.getElementById('node-edit-input');
        if (container && input && this.editingNode) {
            const newText = input.value.trim();
            if (newText !== '') {
                const oldText = this.editingNode.text;
                this.editingNode.text = newText;
                this.editingNode.data.text = newText;
                this.triggerNodeEdit(this.editingNode, oldText, newText);
                // 重新计算布局，因为文本变化可能影响节点大小
                this.calculateLayout();
                this.render();
            }
            container.remove();
            this.editingNode = null;
        }
    }
    
    // 取消编辑
    cancelEditing() {
        const container = document.getElementById('node-edit-container');
        if (container) {
            container.remove();
            this.editingNode = null;
        }
    }
    
    // 渲染思维导图
    // 绘制单个节点及其连线的函数（可在render和renderSubtree中复用）
    drawNode(node, ctx = this.ctx, options = this.options, parentNode = null) {
        // 绘制节点矩形
        ctx.fillStyle = node === this.selectedNode ? options.selectedNodeFill : options.nodeFill;
        ctx.strokeStyle = options.nodeStroke;
        ctx.lineWidth = 1;
        
        // 绘制圆角矩形（使用节点的动态宽度和高度）
        ctx.beginPath();
        ctx.moveTo(node.x + options.cornerRadius, node.y);
        ctx.lineTo(node.x + node.width - options.cornerRadius, node.y);
        ctx.quadraticCurveTo(node.x + node.width, node.y, node.x + node.width, node.y + options.cornerRadius);
        ctx.lineTo(node.x + node.width, node.y + node.height - options.cornerRadius);
        ctx.quadraticCurveTo(node.x + node.width, node.y + node.height, node.x + node.width - options.cornerRadius, node.y + node.height);
        ctx.lineTo(node.x + options.cornerRadius, node.y + node.height);
        ctx.quadraticCurveTo(node.x, node.y + node.height, node.x, node.y + node.height - options.cornerRadius);
        ctx.lineTo(node.x, node.y + options.cornerRadius);
        ctx.quadraticCurveTo(node.x, node.y, node.x + options.cornerRadius, node.y);
        ctx.closePath();
        
        ctx.fill();
        ctx.stroke();
        
        // 计算指示器区域
        const indicatorSize = 16;
        const indicatorX = node.x + node.width - indicatorSize - 8;
        const indicatorY = node.y + node.height / 2;
        
        // 绘制文本
        ctx.fillStyle = options.textColor;
        ctx.font = `${options.fontSize}px ${options.fontFamily}`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        
        // 计算文本可用宽度（为指示器留出空间）
        const textAvailableWidth = node.width - (indicatorSize + 16); // 指示器宽度 + 额外间距
        
        // 绘制多行文本
        if (node.textLines && node.textLines.length > 0) {
            const lineHeight = options.fontSize * 1.2;
            const totalTextHeight = node.textLines.length * lineHeight;
            const textStartY = node.y + (node.height - totalTextHeight) / 2 + lineHeight / 2;
            
            // 重新计算文本换行
            const newTextLines = [];
            node.textLines.forEach(line => {
                let remainingText = line;
                while (remainingText.length > 0) {
                    let lineText = remainingText;
                    let lineWidth = ctx.measureText(lineText).width;
                    
                    // 如果文本宽度超过可用宽度，需要换行
                    if (lineWidth > textAvailableWidth) {
                        // 查找合适的换行点
                        let breakIndex = Math.floor(remainingText.length * (textAvailableWidth / lineWidth));
                        
                        // 向前查找空格或标点作为换行点
                        while (breakIndex > 0 && 
                               !/\s|，|。|、|；|：|！|？|,|\.|;|:|!|\?/.test(remainingText.charAt(breakIndex))) {
                            breakIndex--;
                        }
                        
                        // 如果没找到合适的换行点，就强制在某个字符处换行
                        if (breakIndex === 0) {
                            breakIndex = Math.floor(remainingText.length * (textAvailableWidth / lineWidth));
                        }
                        
                        lineText = remainingText.substring(0, breakIndex + 1);
                        remainingText = remainingText.substring(breakIndex + 1);
                    } else {
                        remainingText = '';
                    }
                    
                    newTextLines.push(lineText);
                }
            });
            
            // 更新节点的文本行
            node.textLines = newTextLines;
            
            // 绘制文本行
            node.textLines.forEach((line, index) => {
                ctx.fillText(
                    line,
                    node.x + textAvailableWidth / 2, // 调整文本水平位置
                    textStartY + index * lineHeight
                );
            });
        } else {
            // 如果没有预处理的文本行，则直接绘制原始文本
            let text = node.text;
            let textWidth = ctx.measureText(text).width;
            
            // 如果文本宽度超过可用宽度，需要截断
            if (textWidth > textAvailableWidth) {
                // 计算可以显示的字符数
                let charCount = Math.floor(text.length * (textAvailableWidth / textWidth));
                text = text.substring(0, charCount) + '...';
            }
            
            ctx.fillText(
                text,
                node.x + textAvailableWidth / 2, // 调整文本水平位置
                node.y + node.height / 2
            );
        }
        
        // 绘制标签（如果有）- 现在绘制在节点框的右侧外部
        if (node.tags && node.tags.length > 0) {
            const tagHeight = options.tagFontSize + options.tagPadding * 2;
            
            // 标签起始X坐标 - 从节点右边框开始，添加一定间距
            const textTagSpacing = 8; // 节点与标签之间的间距
            const tagStartX = node.x + node.width + textTagSpacing;
            
            // 标签起始Y坐标 - 垂直居中
            const tagStartY = node.y + node.height / 2 - tagHeight / 2;
            
            // 保存当前字体设置
            const originalFont = ctx.font;
            const originalTextAlign = ctx.textAlign;
            const originalBaseline = ctx.textBaseline;
            
            // 设置标签字体
            ctx.font = `${options.tagFontSize}px ${options.fontFamily}`;
            ctx.textAlign = 'left';
            ctx.textBaseline = 'middle';
            
            let currentX = tagStartX;
            
            // 绘制每个标签
            node.tags.forEach((tag, index) => {
                // 测量标签文本宽度
                const tagWidth = ctx.measureText(tag).width + options.tagPadding * 2;
                
                // 获取标签颜色配置
                const tagColor = options.tagColors[tag] || options.tagColors.default;
                
                // 绘制标签背景
                ctx.fillStyle = tagColor.bg;
                ctx.beginPath();
                ctx.moveTo(currentX + options.tagCornerRadius, tagStartY);
                ctx.lineTo(currentX + tagWidth - options.tagCornerRadius, tagStartY);
                ctx.quadraticCurveTo(currentX + tagWidth, tagStartY, currentX + tagWidth, tagStartY + options.tagCornerRadius);
                ctx.lineTo(currentX + tagWidth, tagStartY + tagHeight - options.tagCornerRadius);
                ctx.quadraticCurveTo(currentX + tagWidth, tagStartY + tagHeight, currentX + tagWidth - options.tagCornerRadius, tagStartY + tagHeight);
                ctx.lineTo(currentX + options.tagCornerRadius, tagStartY + tagHeight);
                ctx.quadraticCurveTo(currentX, tagStartY + tagHeight, currentX, tagStartY + tagHeight - options.tagCornerRadius);
                ctx.lineTo(currentX, tagStartY + options.tagCornerRadius);
                ctx.quadraticCurveTo(currentX, tagStartY, currentX + options.tagCornerRadius, tagStartY);
                ctx.closePath();
                ctx.fill();
                
                // 绘制标签文本
                ctx.fillStyle = tagColor.text;
                ctx.fillText(
                    tag,
                    currentX + options.tagPadding,
                    tagStartY + tagHeight / 2
                );
                
                // 更新下一个标签的起始位置
                currentX += tagWidth + options.tagMargin;
            });
            
            // 恢复原始字体设置
            ctx.font = originalFont;
            ctx.textAlign = originalTextAlign;
            ctx.textBaseline = originalBaseline;
        }
        
        // 如果有子节点，绘制折叠/展开指示器
        if (node.children && node.children.length > 0) {
            // 只在鼠标悬停或节点被选中时显示指示器
            if (node === this.hoverNode || node === this.selectedNode) {
                // 绘制指示器背景圆
                ctx.beginPath();
                ctx.arc(indicatorX, indicatorY, indicatorSize / 2, 0, Math.PI * 2);
                
                // 使用更柔和的颜色
                ctx.fillStyle = node.collapsed ? '#4CAF50' : '#f5f5f5';
                ctx.fill();
                
                // 添加阴影效果
                ctx.shadowColor = 'rgba(0, 0, 0, 0.1)';
                ctx.shadowBlur = 4;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 2;
                
                // 绘制边框
                ctx.strokeStyle = node.collapsed ? '#388E3C' : '#e0e0e0';
                ctx.lineWidth = 1.5;
                ctx.stroke();
                
                // 重置阴影
                ctx.shadowColor = 'transparent';
                ctx.shadowBlur = 0;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 0;
                
                // 绘制指示器符号（+或-）
                ctx.beginPath();
                ctx.strokeStyle = node.collapsed ? '#ffffff' : '#666666';
                ctx.lineWidth = 2;
                ctx.lineCap = 'round'; // 添加圆角线帽
                
                // 横线
                ctx.moveTo(indicatorX - indicatorSize / 4, indicatorY);
                ctx.lineTo(indicatorX + indicatorSize / 4, indicatorY);
                
                // 竖线（只在折叠状态下绘制）
                if (node.collapsed) {
                    ctx.moveTo(indicatorX, indicatorY - indicatorSize / 4);
                    ctx.lineTo(indicatorX, indicatorY + indicatorSize / 4);
                }
                
                ctx.stroke();
                
                // 存储指示器的点击区域
                node.indicatorRegion = {
                    x: indicatorX - indicatorSize / 2 - 5,
                    y: indicatorY - indicatorSize / 2 - 5,
                    width: indicatorSize + 10,
                    height: indicatorSize + 10
                };
            }
        }
        
        // 如果有父节点，绘制连接线
        if (parentNode) {
            this.drawConnection(node, parentNode, ctx, options);
        }
    }
    
    // 绘制节点之间的连接线
    drawConnection(node, parentNode, ctx = this.ctx, options = this.options) {
        // 绘制连线
        ctx.strokeStyle = options.lineColor;
        ctx.lineWidth = 1.5;
        ctx.beginPath();
        
        // 计算连线起点（从最后一个标签右侧开始，兼容多标签）
        const textTagSpacing = 8; // 节点与标签之间的间距
        let startX = parentNode.x + parentNode.width;
        const startY = parentNode.y + parentNode.height / 2;
        if (parentNode.tags && parentNode.tags.length > 0) {
            // 计算标签起始位置
            let currentX = parentNode.x + parentNode.width + textTagSpacing;
            // 测量标签字体
            const originalFont = ctx.font;
            ctx.font = `${options.tagFontSize}px ${options.fontFamily}`;
            // 遍历标签，更新起点到最后一个标签的右侧
            parentNode.tags.forEach(tag => {
                const tagWidth = ctx.measureText(tag).width + options.tagPadding * 2;
                startX = currentX + tagWidth;
                currentX += tagWidth + options.tagMargin;
            });
            // 恢复字体
            ctx.font = originalFont;
        }
        
        // 终点（子节点左侧垂直中心）
        const endX = node.x;
        const endY = node.y + node.height / 2;
        
        // 计算水平连接线的长度
        const horizontalDistance = endX - startX;
        
        // 检查父节点是否只有一个子节点（且未折叠）
        const hasOnlyOneChild = parentNode.children && 
                               parentNode.children.length === 1 && 
                               !parentNode.collapsed;
        
        // 绘制连接线：单子节点时直线；多子节点时使用拐线
        const verticalThreshold = 5;
        const minSegmentLength = 30; // 最小水平段长度
        const nodeSpacing = 10;      // 与子节点的水平间距
        const dx = endX - startX;
        const dy = Math.abs(endY - startY);

        if (hasOnlyOneChild) {
            // 只有一个子节点，直接画直线
            ctx.moveTo(startX, startY);
            ctx.lineTo(endX, endY);
        } else if (dy > verticalThreshold) {
            // 存在明显垂直偏移，绘制拐线
            if (dx >= 2 * minSegmentLength) {
                // 足够水平距离，使用水平-垂直-水平的三段式
                const midX = startX + dx / 2;
                ctx.moveTo(startX, startY);
                ctx.lineTo(midX, startY);
                ctx.lineTo(midX, endY);
                ctx.lineTo(endX, endY);
            } else {
                // 水平距离不足，先水平至子节点左侧偏移，再竖直，再水平
                const interX = endX - nodeSpacing;
                ctx.moveTo(startX, startY);
                ctx.lineTo(interX, startY);
                ctx.lineTo(interX, endY);
                ctx.lineTo(endX, endY);
            }
        } else {
            // 垂直偏移较小，直接画直线
            ctx.moveTo(startX, startY);
            ctx.lineTo(endX, endY);
        }
        
        ctx.stroke();
    }
    
    // 局部渲染函数 - 只渲染指定节点及其子树
    renderSubtree(node, parentNode = null) {
        const { ctx, options } = this;
        
        // 应用缩放和平移
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        
        // 如果有父节点，需要从父节点开始渲染整个子树
        // 这样可以确保所有兄弟节点及其子节点都被正确渲染
        const startNode = parentNode || node;
        
        // 绘制起始节点
        if (startNode === node) {
            this.drawNode(node, ctx, options, parentNode);
        }
        
        // 递归绘制子节点及其所有后代
        const drawChildrenRecursive = (currentNode, parent) => {
            if (!currentNode.children || currentNode.children.length === 0) return;
            
            // 如果节点是折叠状态，不绘制子节点
            if (currentNode.collapsed) return;
            
            currentNode.children.forEach(child => {
                // 绘制子节点
                this.drawNode(child, ctx, options, parent);
                
                // 递归绘制子节点的所有后代
                drawChildrenRecursive(child, child);
            });
        };
        
        // 从起始节点开始递归绘制整个子树
        drawChildrenRecursive(startNode, startNode);
        
        ctx.restore();
    }
    
    // 完整渲染函数
    render() {
        const { ctx, canvas, options } = this;
        
        // 清除画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        // 应用缩放和平移
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        
        // 递归绘制函数
        const drawNodeRecursive = (node, parentNode = null) => {
            // 绘制当前节点
            this.drawNode(node, ctx, options, parentNode);
            
            // 递归绘制子节点，但只有在节点未折叠时才绘制
            if (node.children && node.children.length > 0 && !node.collapsed) {
                node.children.forEach(child => {
                    drawNodeRecursive(child, node);
                });
            }
        };
        
        // 从根节点开始绘制
        if (this.root) {
            drawNodeRecursive(this.root);
        }
        
        ctx.restore();
    }
    
    // 添加子节点
    addChild(parentNode, text) {
        if (!parentNode) parentNode = this.root;
        
        const newChild = {
            text, // 保留text属性以兼容现有代码
            data: {
                text: text,
                tags: [] // 初始化空标签数组
            },
            tags: [], // 保留直接访问的能力
            level: parentNode.level + 1,
            index: parentNode.children.length,
            uid: this.generateUid(), // 为新节点生成uid
            children: [],
            x: 0,
            y: 0,
            width: this.options.nodeWidth, // 初始宽度，后续会根据文本内容调整
            height: this.options.nodeHeight, // 初始高度，后续会根据文本内容调整
            textLines: [] // 用于存储换行后的文本行
        };
        
        // 保存当前画布状态和布局前的区域
        const { ctx, canvas } = this;
        
        // 查找父节点的父节点（祖父节点），以便更好地处理兄弟节点的渲染
        const findGrandparent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const parent = findGrandparent(currentNode.children[i], targetNode);
                if (parent) return parent;
            }
            
            return null;
        };
        
        // 获取祖父节点（如果存在）
        const grandparent = parentNode !== this.root ? findGrandparent(this.root, parentNode) : null;
        
        // 获取添加节点前的区域，考虑祖父节点的整个子树
        const oldRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parentNode);
        
        // 添加新节点
        parentNode.children.push(newChild);
        
        // 触发添加事件
        this.triggerNodeAdd(newChild, parentNode);
        
        // 重新计算布局
        this.calculateLayout();
        
        // 获取添加节点后的区域，考虑祖父节点的整个子树
        const newRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parentNode);
        
        // 计算合并后的区域，确保覆盖所有可能变化的区域
        const dirtyX = Math.min(oldRegion.x, newRegion.x) - 20;
        const dirtyY = Math.min(oldRegion.y, newRegion.y) - 20;
        const dirtyWidth = Math.max(oldRegion.x + oldRegion.width, newRegion.x + newRegion.width) - dirtyX + this.options.levelGap + 40;
        const dirtyHeight = Math.max(oldRegion.y + oldRegion.height, newRegion.y + newRegion.height) - dirtyY + 40;
        
        // 清除受影响区域
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        ctx.clearRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
        ctx.restore();
        
        // 设置选中节点为新添加的节点
        this.selectedNode = newChild;
        
        // 局部渲染，如果有祖父节点，从祖父节点开始渲染，否则从父节点渲染
        if (grandparent) {
            this.renderSubtree(grandparent);
        } else {
            this.renderSubtree(parentNode);
        }
        
        return newChild;
    }
    
    // 通过传递节点数据的形式添加子节点
    addChildByData(parentNode, nodeData) {
        if (!parentNode) parentNode = this.root;
        
        // 处理节点数据
        const processedData = this.processNode({
            data: {
                text: nodeData.data ? nodeData.data.text : (nodeData.text || '新节点')
            },
            uid: nodeData.uid, // 保留原有uid（如果存在）
            children: nodeData.children || []
        }, parentNode.level + 1, parentNode.children.length);
        
        // 保存当前画布状态和布局前的区域
        const { ctx, canvas } = this;
        
        // 查找父节点的父节点（祖父节点），以便更好地处理兄弟节点的渲染
        const findGrandparent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const parent = findGrandparent(currentNode.children[i], targetNode);
                if (parent) return parent;
            }
            
            return null;
        };
        
        // 获取祖父节点（如果存在）
        const grandparent = parentNode !== this.root ? findGrandparent(this.root, parentNode) : null;
        
        // 获取添加节点前的区域，考虑祖父节点的整个子树
        const oldRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parentNode);
        
        // 添加新节点
        parentNode.children.push(processedData);
        
        // 触发添加事件
        this.triggerNodeAdd(processedData, parentNode);
        
        // 重新计算布局
        this.calculateLayout();
        
        // 获取添加节点后的区域，考虑祖父节点的整个子树
        const newRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parentNode);
        
        // 计算合并后的区域，确保覆盖所有可能变化的区域
        const dirtyX = Math.min(oldRegion.x, newRegion.x) - 20;
        const dirtyY = Math.min(oldRegion.y, newRegion.y) - 20;
        const dirtyWidth = Math.max(oldRegion.x + oldRegion.width, newRegion.x + newRegion.width) - dirtyX + this.options.levelGap + 40;
        const dirtyHeight = Math.max(oldRegion.y + oldRegion.height, newRegion.y + newRegion.height) - dirtyY + 40;
        
        // 清除受影响区域
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        ctx.clearRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
        ctx.restore();
        
        // 设置选中节点为新添加的节点
        this.selectedNode = processedData;
        
        // 局部渲染，如果有祖父节点，从祖父节点开始渲染，否则从父节点渲染
        if (grandparent) {
            this.renderSubtree(grandparent);
        } else {
            this.renderSubtree(parentNode);
        }
        
        return processedData;
    }
    
    // 获取节点及其子树占用的区域
    getNodeRegion(node) {
        if (!node) return { x: 0, y: 0, width: 0, height: 0 };
        
        let minX = node.x;
        let minY = node.y - node.height / 2;
        let maxX = node.x + node.width;
        let maxY = node.y + node.height / 2;
        
        // 递归计算所有子节点的区域
        const calculateChildrenRegion = (currentNode) => {
            if (!currentNode.children || currentNode.children.length === 0) return;
            
            currentNode.children.forEach(child => {
                // 更新当前区域的边界
                minX = Math.min(minX, child.x);
                minY = Math.min(minY, child.y - child.height / 2);
                maxX = Math.max(maxX, child.x + child.width);
                maxY = Math.max(maxY, child.y + child.height / 2);
                
                // 递归处理子节点的子节点
                calculateChildrenRegion(child);
            });
        };
        
        // 开始递归计算
        calculateChildrenRegion(node);
        
        return {
            x: minX,
            y: minY,
            width: maxX - minX,
            height: maxY - minY
        };
    }
    
    // 删除节点
    removeNode(node) {
        if (node === this.root) return; // 根节点不能删除
        
        // 查找节点的父节点
        const findParent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const parent = findParent(currentNode.children[i], targetNode);
                if (parent) return parent;
            }
            
            return null;
        };
        
        const parent = findParent(this.root, node);
        if (!parent) return;
        
        // 查找父节点的父节点（祖父节点），以便更好地处理兄弟节点的渲染
        const findGrandparent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const grandparent = findGrandparent(currentNode.children[i], targetNode);
                if (grandparent) return grandparent;
            }
            
            return null;
        };
        
        // 获取祖父节点（如果存在）
        const grandparent = parent !== this.root ? findGrandparent(this.root, parent) : null;
        
        // 保存当前画布状态
        const { ctx, canvas } = this;
        
        // 获取删除节点前的区域信息
        // 需要同时考虑父节点、祖父节点（如果存在）和要删除的节点区域
        const parentRegion = this.getNodeRegion(parent);
        const nodeRegion = this.getNodeRegion(node);
        const grandparentRegion = grandparent ? this.getNodeRegion(grandparent) : { x: 0, y: 0, width: 0, height: 0 };
        
        // 计算合并后的区域，确保覆盖所有可能变化的区域
        const oldDirtyX = Math.min(parentRegion.x, nodeRegion.x, grandparentRegion.x) - 20;
        const oldDirtyY = Math.min(parentRegion.y, nodeRegion.y, grandparentRegion.y) - 20;
        const oldDirtyWidth = Math.max(
            parentRegion.x + parentRegion.width, 
            nodeRegion.x + nodeRegion.width,
            grandparentRegion.x + grandparentRegion.width
        ) - oldDirtyX + this.options.levelGap + 40;
        const oldDirtyHeight = Math.max(
            parentRegion.y + parentRegion.height, 
            nodeRegion.y + nodeRegion.height,
            grandparentRegion.y + grandparentRegion.height
        ) - oldDirtyY + 40;
        
        // 从父节点的子节点数组中移除
        parent.children = parent.children.filter(child => child !== node);
        
        // 触发删除事件
        this.triggerNodeDelete(node);
        
        // 重新计算索引
        parent.children.forEach((child, index) => {
            child.index = index;
        });
        
        // 取消选中
        if (this.selectedNode === node) {
            this.selectedNode = null;
        }
        
        // 重新计算布局
        this.calculateLayout();
        
        // 获取删除节点后的区域
        const newParentRegion = this.getNodeRegion(parent);
        const newGrandparentRegion = grandparent ? this.getNodeRegion(grandparent) : { x: 0, y: 0, width: 0, height: 0 };
        
        // 计算最终的清除区域，确保覆盖删除前后所有可能变化的区域
        const dirtyX = Math.min(oldDirtyX, newParentRegion.x - 20, newGrandparentRegion.x - 20);
        const dirtyY = Math.min(oldDirtyY, newParentRegion.y - 20, newGrandparentRegion.y - 20);
        const dirtyWidth = Math.max(
            oldDirtyX + oldDirtyWidth, 
            newParentRegion.x + newParentRegion.width + this.options.levelGap + 40,
            newGrandparentRegion.x + newGrandparentRegion.width + this.options.levelGap + 40
        ) - dirtyX;
        const dirtyHeight = Math.max(
            oldDirtyY + oldDirtyHeight, 
            newParentRegion.y + newParentRegion.height + 40,
            newGrandparentRegion.y + newGrandparentRegion.height + 40
        ) - dirtyY;
        
        // 清除受影响区域
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        ctx.clearRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
        ctx.restore();
        
        // 局部渲染，如果有祖父节点，从祖父节点开始渲染，否则从父节点渲染
        if (grandparent) {
            this.renderSubtree(grandparent);
        } else {
            this.renderSubtree(parent);
        }
    }

    // 触发节点选择事件
    triggerNodeSelect(node) {
        if (this.eventCallbacks.onNodeSelect) {
            this.eventCallbacks.onNodeSelect(node);
        }
    }

    // 触发节点激活事件
    triggerNodeActivate(node) {
        if (this.eventCallbacks.onNodeActivate) {
            this.eventCallbacks.onNodeActivate(node);
        }
    }

    // 触发节点编辑事件
    triggerNodeEdit(node, oldText, newText) {
        if (this.eventCallbacks.onNodeEdit) {
            this.eventCallbacks.onNodeEdit(node, oldText, newText);
        }
    }

    // 触发节点删除事件
    triggerNodeDelete(node) {
        if (this.eventCallbacks.onNodeDelete) {
            this.eventCallbacks.onNodeDelete(node);
        }
    }

    // 触发节点添加事件
    triggerNodeAdd(node, parentNode) {
        if (this.eventCallbacks.onNodeAdd) {
            this.eventCallbacks.onNodeAdd(node, parentNode);
        }
    }

    // 触发节点折叠事件
    triggerNodeCollapse(node) {
        if (this.eventCallbacks.onNodeCollapse) {
            this.eventCallbacks.onNodeCollapse(node);
        }
    }

    // 触发节点展开事件
    triggerNodeExpand(node) {
        if (this.eventCallbacks.onNodeExpand) {
            this.eventCallbacks.onNodeExpand(node);
        }
    }

    // 复制节点及其子树
    copyNode(node) {
        if (!node) return null;
        
        // 递归复制节点及其子树
        const copyNodeRecursive = (sourceNode) => {
            const newNode = {
                text: sourceNode.text,
                data: {
                    text: sourceNode.text,
                    tags: [...(sourceNode.tags || [])]
                },
                tags: [...(sourceNode.tags || [])],
                level: sourceNode.level,
                index: sourceNode.index,
                uid: this.generateUid(),
                children: [],
                x: 0,
                y: 0,
                width: sourceNode.width,
                height: sourceNode.height,
                textLines: [...(sourceNode.textLines || [])],
                collapsed: sourceNode.collapsed
            };
            
            // 递归复制子节点
            if (sourceNode.children && sourceNode.children.length > 0) {
                newNode.children = sourceNode.children.map(child => copyNodeRecursive(child));
            }
            
            return newNode;
        };
        
        // 复制节点
        const copiedNode = copyNodeRecursive(node);
        
        // 查找父节点
        const findParent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const parent = findParent(currentNode.children[i], targetNode);
                if (parent) return parent;
            }
            
            return null;
        };
        
        const parent = findParent(this.root, node);
        if (!parent) return null;
        
        // 查找父节点的父节点（祖父节点）
        const findGrandparent = (currentNode, targetNode) => {
            if (!currentNode || !currentNode.children) return null;
            
            for (let i = 0; i < currentNode.children.length; i++) {
                if (currentNode.children[i] === targetNode) {
                    return currentNode;
                }
                
                const grandparent = findGrandparent(currentNode.children[i], targetNode);
                if (grandparent) return grandparent;
            }
            
            return null;
        };
        
        // 获取祖父节点（如果存在）
        const grandparent = parent !== this.root ? findGrandparent(this.root, parent) : null;
        
        // 保存当前画布状态
        const { ctx, canvas } = this;
        
        // 获取复制前的区域
        const oldRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parent);
        
        // 添加复制的节点
        parent.children.push(copiedNode);
        
        // 触发添加事件
        this.triggerNodeAdd(copiedNode, parent);
        
        // 重新计算布局
        this.calculateLayout();
        
        // 获取复制后的区域
        const newRegion = grandparent ? this.getNodeRegion(grandparent) : this.getNodeRegion(parent);
        
        // 计算合并后的区域
        const dirtyX = Math.min(oldRegion.x, newRegion.x) - 20;
        const dirtyY = Math.min(oldRegion.y, newRegion.y) - 20;
        const dirtyWidth = Math.max(oldRegion.x + oldRegion.width, newRegion.x + newRegion.width) - dirtyX + this.options.levelGap + 40;
        const dirtyHeight = Math.max(oldRegion.y + oldRegion.height, newRegion.y + newRegion.height) - dirtyY + 40;
        
        // 清除受影响区域
        ctx.save();
        ctx.translate(this.offsetX, this.offsetY);
        ctx.scale(this.scale, this.scale);
        ctx.clearRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
        ctx.restore();
        
        // 局部渲染
        if (grandparent) {
            this.renderSubtree(grandparent);
        } else {
            this.renderSubtree(parent);
        }
        
        // 设置选中节点为复制的节点
        this.selectedNode = copiedNode;
        this.triggerNodeSelect(copiedNode);
        
        return copiedNode;
    }
}

// 初始化思维导图
document.addEventListener('DOMContentLoaded', () => {
    const mindmap = new MindMap('mindmap');
    // 将mindmap实例暴露给window对象，以便其他脚本可以访问
    window.mindmapInstance = mindmap;
});